package cn.opencodes.framework.core.redis;

import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * redis分布式锁实现
 * @author HJ
 */
public class RedisDistributedLock {
	private Logger log = LoggerFactory.getLogger(RedisDistributedLock.class);

	@Autowired
	private RedissonClient redissonClient;

	/**
	 * 加锁
	 * @param lock 分布式锁的key（唯一性）
	 * @param lockTimeout 超时毫秒
	 * @param retryTimes 尝试失败次数
	 * @param sleepMillis 获取锁等待毫秒
	 * @return 是否成功拿到锁
	 */
	public boolean lock(RLock lock, long lockTimeout, int retryTimes, long sleepMillis){
		boolean result = false;
        try {
        	result =  lock.tryLock(sleepMillis, lockTimeout, TimeUnit.MILLISECONDS);
            while ((!result) && retryTimes-- > 0) {
            	log.debug("get redisDistributeLock failed, retrying..."+ retryTimes);
    			result = lock.tryLock(sleepMillis, lockTimeout, TimeUnit.MILLISECONDS);
    		}
        } catch (InterruptedException e) {
        	e.printStackTrace();
        }
        return result;
	}
	
	/**
	 * 解锁
	 * @param lockKey 分布式锁的key（唯一性）
	 */
	public void unlock(String key) {
		RLock lock = redissonClient.getLock(key);
        lock.unlock();
	}
	
	public void unlock(RLock lock) {
        lock.unlock();
	}
	
	public RLock getLock(String key){
		return redissonClient.getLock(key);
	}
	
	
	
	/*private ThreadLocal<String> lockFlag = new ThreadLocal<>();

	@Autowired
	private RedisUtils redis;
	
	@Autowired
    private ValueOperations<String, Object> valueOperations;*/

	/*public String lock(String key, long lockTimeout, int retryTimes, long sleepMillis) {
		lockTimeout = lockTimeout + System.currentTimeMillis();
		boolean result = lock(key, lockTimeout);
		// 如果获取锁失败，按照传入的重试次数进行重试
		while ((!result) && retryTimes-- > 0) {
			try {
				log.debug("get redisDistributeLock failed, retrying..."+ retryTimes);
				Thread.sleep(sleepMillis);
			} catch (InterruptedException e) {
				log.warn("Interrupted!", e);
				Thread.currentThread().interrupt();
			}
			result = lock(key, lockTimeout);
		}
		if (result) {
			String requestId = IDUtils.guid();
			lockFlag.set(requestId);
			return requestId;
		}
		return null;
	}*/


	/*public boolean unlock(String key, String requestId) {
		try {
			// 释放锁的时候，有可能因为持锁之后方法执行时间大于锁的有效期，此时有可能已经被另外一个线程持有锁，所以同一线程的才直接删除
			if (StringUtils.isNotEmpty(requestId) && lockFlag.get().equals(requestId)) {
				unlock(key);
			}
		} catch (Exception e) {
			log.error("unlock redisDistributeLock occured an exception", e);
		} finally {
			lockFlag.remove();
		}
		return false;
	}*/
	
	/*
	 * 加锁
	 * @param lockKey 分布式锁的key（唯一性）
	 * @param lockTimeout 当前时间戳 + 超时毫秒
	 * @return 是否成功拿到锁
	 */
	/*private boolean lock(String lockKey, long lockTimeout) {
		// 1. 设置锁
		if (valueOperations.setIfAbsent(lockKey, lockTimeout)) {
			return true;
		}
		// 2. 锁设置失败，拿到当前锁
		Long currentValue = redis.get(lockKey, long.class);
		// 3. 判断当前锁过期,允许别的线程重新获取
		if (currentValue!=null && currentValue.longValue() < System.currentTimeMillis()) {
			// 4. 锁已过期 ，设置新锁同时得到上一个锁。如果不相等，说明这个锁又被别的请求获取走
			Long oldValue = (Long)valueOperations.getAndSet(lockKey, ++lockTimeout);
			// 5. 确认新锁是否设置成功（判断当前锁与上一个锁是否相等）
			if (oldValue!=null && oldValue.longValue()==currentValue.longValue()) {
				// 此处只会有一个线程拿到锁
				return true;
			}
		}
		return false;
	}*/
	
	/*
	 * 解锁
	 * @param lockKey 分布式锁的key（唯一性）
	 * @param lockTimeout 加锁时使用的超时时间戳
	 */
	/*private void unlock(String lockKey) {
		try {
			redis.delete(lockKey);
		} catch (Exception e) {
			log.error("【redis分布式锁】解锁异常，{}", e);
		}
	}*/
}
